package mdt.figure;

import org.tigris.gef.presentation.Fig;
import org.tigris.gef.presentation.FigGroup;
import org.tigris.gef.presentation.FigNode;
import mdt.action.SetFigShapeAttrAction;
import mdt.action.SetFigTextAttrAction;
import mdt.model.INodeModel;
import mdt.model.MDTModel;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.util.Iterator;
import java.util.Vector;

/**
 * Created by xiaobyu on 6/17/2016.
 */
public class FigNodeEditable extends FigNode implements KeyListener, FigMDT{

    private TextType textType;
    protected FigTextMDT figText;

    public static final long serialVersionUID = 1l;

    public FigNodeEditable(INodeModel model, FigNodeEditable.TextType textType) {
        this.textType = textType;
        initTextFig(model);
        addFig(figText);
        setOwner(model);
    }

    public void setOwner(Object owner) {
        super.setOwner(owner);
        if (owner != null) {
            figText.setText(((INodeModel)getOwner()).getName());
        }
    }

    public void setDashed(boolean dashed) {
        figText.setDashed(dashed);
        super.setDashed(dashed);
    }

    protected void initTextFig(INodeModel model) {
        String content = model == null ? "" : model.getName();
        switch (textType) {
            case SINGLE_LINE:
                figText = new FigNamed(null, content);
                break;
            case MULTI_LINE:
                figText = new FigMultiLineText(null);
                figText.setText(content);
                break;
        }
        figText.setEditable(true);
        figText.setLineWidth(0);
        figText.setFilled(true);
    }

    public FigTextMDT getFigText() {
        return figText;
    }

    public Point getFirstPoint() {
        return new Point(_x, _y + _h / 2);
    }

    public int getNumPoints() {
        return 2;
    }

    public Point getLastPoint() {
        return new Point(_x + _w, _y + _h / 2);
    }

    public Point getPoint(int i) {
        if (i == 0) {
            return getFirstPoint();
        } else if (i == 1) {
            return getLastPoint();
        } else {
            return null;
        }
    }

    public FigNodeEditable cloneFig() {
        FigNodeEditable cloned = (FigNodeEditable)super.clone();
        int idx = getFigs().indexOf(figText);
        cloned.figText = (FigTextMDT) cloned.getFigAt(idx);
        return cloned;
    }

    public INodeModel cloneOwner() {
        return  (INodeModel)((MDTModel)getOwner()).clone();
    }

    public Object clone() {
        FigNodeEditable cloned = (FigNodeEditable)cloneFig();
        INodeModel clonedOwner = cloneOwner();
        cloned.setOwner(clonedOwner);

        if (!clonedOwner.getName().equals(((INodeModel)getOwner()).getName())) {
            cloned.updateBounds();
        }

        return cloned;
    }

    public void propertyChange(final PropertyChangeEvent pve) {
        final Object src = pve.getSource();
        final String pName = pve.getPropertyName();

        // We handle and consume editing events
        if (pName.equals("editing") && Boolean.FALSE.equals(pve.getNewValue())) {
            // resize the FigNode to accommodate the new text
            updateBounds();
            endTrans();
            INodeModel nm = (INodeModel)getOwner();
            if (nm != null) {
                nm.setName(figText.getText());
            }
        } else if (pName.equals("editing") && Boolean.TRUE.equals(pve.getNewValue())) {
            // do nothing

        } else if (pName.equals("bounds") && pve.getSource() == figText) {
            // ?
        } else {
            super.propertyChange(pve);
        }
    }

    public Dimension getMinimumSize() {
        return figText.getMinimumSize();
    }

    public void mouseClicked(MouseEvent me) {
        if (me.isConsumed()) {
            return;
        }
        if (me.getClickCount() >= 2 && !(me.isPopupTrigger() || me.getModifiers() == InputEvent.BUTTON3_MASK)
                && getOwner() != null) {
            Rectangle r = new Rectangle(me.getX() - 2, me.getY() - 2, 4, 4);
            Fig f = hitFig(r);
            if (f instanceof MouseListener && f.isVisible()) {
                ((MouseListener) f).mouseClicked(me);
            } else if (f instanceof FigGroup && f.isVisible()) {
                // this enables direct text editing for sub figs of a
                // FigGroup object:
                Fig f2 = ((FigGroup) f).hitFig(r);
                if (f2 instanceof MouseListener) {
                    ((MouseListener) f2).mouseClicked(me);
                }
            }
        }
    }

    protected void setBoundsImpl(int x, int y, int w, int h) {
        Rectangle oldBounds = getBounds();
        Dimension minSize = getMinimumSize();
        w = (int) Math.max(w, minSize.getWidth());
        h = (int) Math.max(h, minSize.getHeight());
        setTextFigBounds(x, y, w, h);
        calcBounds(); // _x = x; _y = y; _w = w; _h = h;
        firePropChange("bounds", oldBounds, getBounds());
        updateEdges();
    }

    protected void setTextFigBounds(int x, int y, int w, int h) {
        figText.setBounds(x, y, w, h);
    }

    public void keyPressed(KeyEvent ke) {
        if (ke.isConsumed() || getOwner() == null) {
            return;
        }
        figText.keyPressed(ke);
    }

    public void keyReleased(KeyEvent ke) {
        if (ke.isConsumed() || getOwner() == null) {
            return;
        }
        figText.keyReleased(ke);
    }

    public void keyTyped(KeyEvent ke) {
        if (ke.isConsumed() || getOwner() == null) {
            return;
        }
        figText.keyTyped(ke);
    }

    @Override
    public void renderingChanged() {
        updateBounds();
        damage();
    }

    public void translateCloned(int dx, int dy) {
        translate(dx, dy);
    }

    public void updateBounds() {
        Rectangle bbox = getBounds();
        Dimension minSize = getMinimumSize();
        bbox.width = Math.max(bbox.width, minSize.width);
        bbox.height = Math.max(bbox.height, minSize.height);
        setBounds(bbox.x, bbox.y, bbox.width, bbox.height);
    }

    public void shrinkToMinimumBounds() {
        Dimension figTextMinSize = figText.getMinimumSize();
        figText.setWidth(figTextMinSize.width);
        figText.setHeight(figTextMinSize.height);

        Rectangle bbox = getBounds();
        Dimension minSize = getMinimumSize();
        bbox.width = minSize.width;
        bbox.height = minSize.height;
        setBounds(bbox.x, bbox.y, bbox.width, bbox.height);
    }

    public Vector getPopUpActions(MouseEvent me) {
        Vector popUpActions = super.getPopUpActions(me);
        popUpActions.add(new JSeparator());
        popUpActions.add(new JMenuItem(new SetFigShapeAttrAction()));
        popUpActions.add(new JMenuItem(new SetFigTextAttrAction()));
        return popUpActions;
    }

    public void appendSvg(StringBuffer sb) {
        sb.append("<g id='").append(getId()).append("' class='").append(
                getClass().getName()).append("'>");
        sb.append("<g id='").append(getId() + ".g0'");
        appendSvgStyle(sb);
        sb.append(">");
        for (Iterator it = getFigs().iterator(); it.hasNext();) {
            Fig fig = (Fig) it.next();
            if (fig == figText) continue;
            //if (fig.isVisible()) {
                fig.appendSvg(sb);
            //}
        }
        sb.append("</g>");
        figText.appendSvg(sb);
        sb.append("</g>");
    }


    public static enum TextType {
        SINGLE_LINE,
        MULTI_LINE
    }
}